package com.xxgg.common.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.xxgg.common.result.ResultCodeEnum;
import com.xxgg.common.result.ResultJSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @description: 全局异常处理
 * @author: 先谢郭嘉
 * @create: 2020-11-22 17:49
 */
@ControllerAdvice
@Slf4j
public class GlobalException {

	/**
	 * 在当前类每个方法进入之前触发的操作
	 * @param request
	 * @throws IOException
	 */
	@ModelAttribute
	public void get(HttpServletRequest request) throws IOException {
		
	}

	/**
	 * 全局异常拦截（拦截项目中的所有异常）
	 * @param e
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@ExceptionHandler
	public ResultJSON handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 打印堆栈，以供调试
		log.error("全局异常---------------");
		e.printStackTrace(); 

		// 不同异常返回不同状态码
		if (e instanceof NotLoginException) {
			// 如果是未登录异常
			NotLoginException ee = (NotLoginException) e;
			return new ResultJSON<>(ResultCodeEnum.NOT_LOGIN.getCode(),
					ResultCodeEnum.NOT_LOGIN.getMessage(),ee.getMessage());
		} else if(e instanceof NotRoleException) {
			// 如果是角色异常
			NotRoleException ee = (NotRoleException) e;
			return new ResultJSON<>(ResultCodeEnum.NOT_ROLE.getCode(),
					ResultCodeEnum.NOT_ROLE.getMessage(),"无此角色：" + ee.getRole());
		} else if(e instanceof NotPermissionException) {
			// 如果是权限异常
			NotPermissionException ee = (NotPermissionException) e;
			return new ResultJSON<>(ResultCodeEnum.NOT_JUR.getCode(),
					ResultCodeEnum.NOT_JUR.getMessage(),"无此权限：" + ee.getCode());
		}  else {
			// 普通异常, 输出：500 + 异常信息
			return ResultJSON.error().message(e.getMessage());
		}
	}


	/**
	 * 全局异常拦截（拦截项目中的NotLoginException异常）
	 * @param nle
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@ExceptionHandler(NotLoginException.class)
	public ResultJSON<Object> handlerNotLoginException(NotLoginException nle, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 打印堆栈，以供调试
		log.error("NotLoginException异常---------------");
		nle.printStackTrace();

		// 判断场景值，定制化异常信息
		if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
			// 未能读取到有效Token
			return ResultJSON.fail()
					.code(ResultCodeEnum.NOT_TOKEN.getCode())
					.message(ResultCodeEnum.NOT_TOKEN.getMessage());
		} else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
			// token无效
			return ResultJSON.fail()
					.code(ResultCodeEnum.INVALID_TOKEN.getCode())
					.message(ResultCodeEnum.INVALID_TOKEN.getMessage());
		} else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
			// token已过期
			return ResultJSON.fail()
					.code(ResultCodeEnum.TOKEN_TIMEOUT.getCode())
					.message(ResultCodeEnum.TOKEN_TIMEOUT.getMessage());
		} else if(nle.getType().equals(NotLoginException.BE_REPLACED)) {
			// token已被顶下线
			return ResultJSON.fail()
					.code(ResultCodeEnum.BE_REPLACED.getCode())
					.message(ResultCodeEnum.BE_REPLACED.getMessage());
		} else if(nle.getType().equals(NotLoginException.KICK_OUT)) {
			// token已被踢下线
			return ResultJSON.fail()
					.code(ResultCodeEnum.KICK_OUT.getCode())
					.message(ResultCodeEnum.KICK_OUT.getMessage());
		} else {
			// 当前会话未登录
			return ResultJSON.fail()
					.code(ResultCodeEnum.NOT_LOGIN.getCode())
					.message(ResultCodeEnum.NOT_LOGIN.getMessage());
		}
	}


	/**
	 * 异常拦截（拦截项目中的ApiException异常）
	 * @param e
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@ExceptionHandler(ApiException.class)
	public ResultJSON myException(ApiException e, HttpServletRequest request, HttpServletResponse response){

		// 打印堆栈，以供调试
		log.error("ApiException异常---------------");
		e.printStackTrace();

		// ApiException异常, 输出：500 + 异常信息
		return ResultJSON.error().message(e.getMessage());
	}

	/**
	 * 参数异常拦截（拦截项目中的BindException异常）
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(value = BindException.class)
	public ResultJSON exceptionHandle(BindException exception) {
		BindingResult result = exception.getBindingResult();
		StringBuilder errorMsg = new StringBuilder();

		List<FieldError> fieldErrors = result.getFieldErrors();
		fieldErrors.forEach(error -> {
			log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
			errorMsg.append(error.getDefaultMessage()).append("!");
		});
		return ResultJSON.fail().message(errorMsg.toString());
	}

	/**
	 * 参数异常拦截（拦截项目中的MethodArgumentNotValidException异常）
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	public ResultJSON MyExceptionHandle(MethodArgumentNotValidException exception) {

		BindingResult result = exception.getBindingResult();
		StringBuilder errorMsg = new StringBuilder();

		List<FieldError> fieldErrors = result.getFieldErrors();
		fieldErrors.forEach(error -> {
			log.error("field: " + error.getField() + ", msg:" + error.getDefaultMessage());
			errorMsg.append(error.getDefaultMessage()).append("!");
		});

		return ResultJSON.fail().message(errorMsg.toString());
	}
}
